package sim.ring.gui.treedata;

import java.util.ArrayList;

import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;

public class MethodTreeContentProvider implements ITreeContentProvider,
		IChangeListener {
	
	protected TreeViewer viewer;
	protected Folder rootFolder;
	

	@Override
	public void dispose() { }

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		this.viewer = (TreeViewer)viewer;
		if (oldInput != null) {
			removeAllListeners(oldInput);
		}
		if (newInput != null) {
			if (newInput instanceof Folder) {
				rootFolder = (Folder)newInput;
			}
			addListeners(newInput);
		}
	}
	
	private void addListeners(Object newInput) {
		if (newInput instanceof Folder) {
			Folder f = (Folder)newInput;
			f.addChangeListener(this);
			for (Folder f1 : f.getFolders()) {
				addListeners(f1);
			}
			for (Category c : f.getCategories()) {
				addListeners(c);
			}
		} else if (newInput instanceof Category) {
			Category c = (Category)newInput;
			c.addChangeListener(this);
		}
	}

	private void removeAllListeners(Object oldInput) {
		if (oldInput instanceof Folder) {
			Folder f = (Folder)oldInput;
			f.removeChangeListener(this);
			for (Folder f1 : f.getFolders()) {
				removeAllListeners(f1);
			}
			for (Category c : f.getCategories()) {
				removeAllListeners(c);
			}
		} else if (oldInput instanceof Category) {
			Category c = (Category)oldInput;
			c.removeChangeListener(this);
		}
	}


	@Override
	public void add(ChangeEvent event) {
		Object folder = ((DataModel)(event.getTarget())).getParent();
		viewer.refresh(folder, false);
	}

	@Override
	public void remove(ChangeEvent event) {
		add(event);
	}

	@Override
	public Object[] getElements(Object inputElement) {
		return getChildren(inputElement);
	}

	@Override
	public Object[] getChildren(Object parentElement) {
		ArrayList<Object> result = new ArrayList<Object>();
		if (parentElement instanceof Folder) {
			Folder f = (Folder)parentElement;
			result.addAll(f.getFolders());
			result.addAll(f.getCategories());
			result.addAll(f.getMethods());
		} else if (parentElement instanceof Category) {
			Category c = (Category)parentElement;
			result.addAll(c.getMethods());
		}
		return result.toArray();
	}

	@Override
	public Object getParent(Object element) {
		if (element instanceof DataModel)
			return ((DataModel)element).getParent();
		return null;
	}

	@Override
	public boolean hasChildren(Object element) {
		return getChildren(element).length > 0;
	}
	
	public void addNewFolder() {
		Folder targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			while (!(selectedElement instanceof Folder)) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = (Folder)selectedElement;
		}
		Folder f_new = new Folder("New folder");
		targetFolder.add(f_new);
		add(new ChangeEvent(f_new));
	}
	
	public void addNewFolder(String folderName) {
		Folder targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			while (!(selectedElement instanceof Folder)) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = (Folder)selectedElement;
		}
		Folder f_new = new Folder(folderName);
		targetFolder.add(f_new);
		add(new ChangeEvent(f_new));
	}
	
	public void addNewCategory() {
		Folder targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			while (!(selectedElement instanceof Folder)) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = (Folder)selectedElement;
		}
		Category c_new = new Category("New category");
		targetFolder.add(c_new);
		add(new ChangeEvent(c_new));
	}
	
	public void addNewCategory(String categoryName) {
		Folder targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			while (!(selectedElement instanceof Folder)) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = (Folder)selectedElement;
		}
		Category c_new = new Category(categoryName);
		targetFolder.add(c_new);
		add(new ChangeEvent(c_new));
	}
	
	public void addNewMethod() {
		DataModel targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			if (selectedElement instanceof TMethod) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = selectedElement;
		}
		if (targetFolder instanceof Folder || targetFolder instanceof Category) {
			TMethod m_new = new TMethod();
			targetFolder.add(m_new);
			add(new ChangeEvent(m_new));
		}
	}
	
	public void addNewMethod(TMethod newMethod) {
		DataModel targetFolder;
		if (viewer.getSelection().isEmpty()) {
			targetFolder = rootFolder;
		} else {
			IStructuredSelection currentSelection = (IStructuredSelection)viewer.getSelection();
			DataModel selectedElement = (DataModel)currentSelection.getFirstElement();
			if (selectedElement instanceof TMethod) {
				selectedElement = selectedElement.getParent();
			}
			targetFolder = selectedElement;
		}
		if (targetFolder instanceof Folder || targetFolder instanceof Category) {
			targetFolder.add(newMethod);
			add(new ChangeEvent(newMethod));
		}
	}

}
